/* 
 * File:   BasicCmd.cpp
 * Author: Fei Fan
 * E-mail: ffinuyasha@sina.com
 * Copyright © 2013 Fei Fan, All Rights Reserved
 */

#include"FileMng.h"

//////////////////////////////////////////////////////////////////////////
//
//                                基本操作指令
//
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////
//
//                 Load File
//
/////////////////////////////////////

int loadFile(char *filename, short loadType) {
    int i, j, k, inode, memoNum,remoteFlag;
    short size, sect;
    char terName[50],path[50];
    HeadIndex headIndex[INDEX_MAX];
    Zone myZone;
    
    remoteFlag=IS_LOCAL;
    strcpy(terName,"\0");
    if (isRemote(filename,terName,path)==SUCCESS) {
       // printf("tN %s is remote!!!!!\n",terName);
        remoteFlag=IS_REMOTE;
        
        if(isExist(terName,FIND_TERMINAL)==FAIL){
            printf("Terminal %s does NOT exist!\n",terName);
            return FAIL;
        }
        
        loadHeadIndex(headIndex,terName);
        inode = getHeadNode(headIndex,path);
        if (inode == FAIL) {
            //unloadHeadIndex(headIndex,terName);
            return FAIL;
        }
        
        //权限审核
        // 若loadType%PMS==0 则执行
        // 若loadType%PMS!=0 则无权访问
        if (loadType % headIndex[inode].PMS != 0 && strcmp(path,"/sys/vac")) {
            printf("NO PERMISSION to execute %s!\n", filename);
            //unloadHeadIndex(headIndex,terName);
            return FAIL;
        }
        
    }
    else{
        //printf("tN %s is local!!!!!!!!!!!\n",terName);
        //查找该文件
        loadHeadIndex(headIndex,terName);
        inode = getHeadNode(headIndex, filename);
        if (inode == FAIL) {
            //unloadHeadIndex(headIndex,terName);
            return FAIL;
        }
    }
    //修改头索引
    if (loadType <= 2) {
        if (headIndex[inode].rdCnt > 0 || headIndex[inode].wrtCnt > 0) {
            printf("File %s is BEING readed or writed, please try again later.\n", filename);
            return FAIL;
        } else {
            headIndex[inode].wrtCnt++;
            //写回
            unloadHeadIndex(headIndex,terName);
            
            loadHeadIndex(headIndex,terName);
            if(headIndex[inode].wrtCnt > 1 || headIndex[inode].rdCnt > 0){
                headIndex[inode].wrtCnt--;
                unloadHeadIndex(headIndex,terName);
                return FAIL;
            } 
        }
    } else {
        if (headIndex[inode].wrtCnt > 0) {
            printf("File %s is BEING writed, please try again later.\n", filename);
            return FAIL;
        } else {
            headIndex[inode].rdCnt++;
            //写回
            unloadHeadIndex(headIndex,terName);
            
            loadHeadIndex(headIndex,terName);
            if(headIndex[inode].wrtCnt > 0){
                headIndex[inode].rdCnt--;
                unloadHeadIndex(headIndex,terName);
                return FAIL;
            }
            
        }
    }

    
    
    getMemoZone(&myZone);
    //插入打开文件表并装入内存
    while (myZone.openedSize + headIndex[inode].size > STRMEMO_MAX || myZone.openedSum == OPEN_MAX) {
        printf("TOO MANY files have loaded, please unload some of them!\n");
        printf("Please input the file name to be unloaded:");
        char newFileName[50];
        gets(newFileName);
        unloadFile(newFileName);
    }
    getMemoZone(&myZone);
    size = headIndex[inode].size;
    for (j = 0; j < OPEN_MAX; j++) {
        if (myZone.openFileMemo[j].access == FAIL) {
            myZone.openedSum++;
            strcpy(myZone.openFileMemo[j].name, filename);
            myZone.openFileMemo[j].access = ACCESS;
//            strcpy(openFileMemo[j].terName,terName);
            myZone.openFileMemo[j].mod = 0;
            myZone.openFileMemo[j].loadType = loadType;
            myZone.openFileMemo[j].size = size;
            myZone.openFileMemo[j].type = headIndex[inode].type;
            for (k = 0; k < size; k++) {
                sect = headIndex[inode].sects[k];
                memoNum = loadToMemo(&myZone,sect,terName); //装入内存
                myZone.openFileMemo[j].sectMemo[k][0] = sect;
                myZone.openFileMemo[j].sectMemo[k][1] = memoNum;
            }
            break;

        }
    }
    putMemoZone(&myZone);
 //   printf("j in load %d",j);
    return j; //返回在openFileMemo表的位置


}

////////////////////////////////////////
//
//                 Create File
//
////////////////////////////////////////

int createFile(char *path, char *filename) {
    char spms[5], strDir[50], temp[50];
    int vNum, i,res;
    char ctype;
    short type, pms, openNum;
    int sects[SECT_MAX];
    long nowTime;
    HeadIndex headIndex[INDEX_MAX];
    Zone myZone;

//    printf("createFile\n");
//        FILE *fp;
//    char filenameTemp[50];
//    VacantTable VacantBlock;
//    fp = fopen(SecterPath(filenameTemp, SECT_VACDIR), "r");
//    fread(&VacantBlock, sizeof (VacantTable), 1, fp);
//    int tempN=VacantBlock.sectNum;
//    printf("%hd\n",tempN);
//    for(int tempI=0;tempI<tempN;tempI++) printf("start:%hd      len:%hd\n",VacantBlock.start[tempI],VacantBlock.len[tempI]);
//    fclose(fp);
    
    //打开此路径
    openNum = loadFile(path, WRITE);
    if (openNum == FAIL) {
        printf("Load directory FAILED!\n");
        return FAIL;
    }
    
    getMemoZone(&myZone);
    if (myZone.openFileMemo[openNum].type != TYPE_DIR) {
        printf("The directory that user input is NOT a directory file!\n");
        unloadFile(path);
        return FAIL;
    }

    //验证重复
    strcpy(temp, path);
    if(strcmp(temp,"/")) strcat(temp, "/");
    strcat(temp, filename);
    loadHeadIndex(headIndex,"\0");
    for (i = 0; i < INDEX_MAX; i++) {
        if (strcmp(headIndex[i].name, temp) == 0) {
            printf("The file does exist ALREADY!\n");
            unloadFile(path);
            //Do not unloadHeadIndex(headIndex);

            return FAIL;
        }
    }
    //unloadHeadIndex(headIndex,"\0");
    //分配磁盘空间
    res = getVacSects(sects,1,"\0");
    if (res !=SUCCESS) {
        unloadFile(path);
        return FAIL;
    }

    printf("Please input the type of the file\n([d]Directory File [f]Normal File):");
    while (1) {
        ctype=getche();
        printf("\n");
        if (ctype == 'd') {
            type = TYPE_DIR;
            break;
        } else if (ctype == 'f') {
            type = TYPE_FILE;
            break;
        } else {
            printf("The value you entered is NOT valid, please input again!\n");
        }
    }

    printf("Please choose the permission accredited to other users\n");
    printf("([r]READ ONLY [w]WRITE ONLY [rw]READ AND WRITE [no]NONE):\n");
    while (1) {
        gets(spms);
        if (strcmp(spms, "rw") == 0) {
            pms = RANDW;
            break;
        } else if (strcmp(spms, "r") == 0) {
            pms = READ;
            break;
        } else if (strcmp(spms, "w") == 0) {
            pms = WRITE;
            break;
        } else if (strcmp(spms, "no") == 0) {
            pms = NONE;
            break;
        } else {
            printf("The value you entered is NOT valid, please input again!\n");
        }
    }
  

    time(&nowTime);

    strDir[0] = '\0';
    buildDir(strDir, filename, spms, ctype, nowTime);
    appendContent(strDir, openNum);
    res=unloadFile(path);
    printf("File ");
            
    loadHeadIndex(headIndex,"\0");

    if(strcmp(path,"/")) strcat(path, "/");
    strcat(path, filename);

    addHead(headIndex, path, pms, sects[0], type, 1, nowTime);
    unloadHeadIndex(headIndex,"\0");

    //loadHeadIndex(headIndex);

    return SUCCESS;
}

////////////////////////////////////////////
//
//                 Unload File
//
////////////////////////////////////////////

int unloadFile(char *filename) {
    int i, j, k, vNum,n, sectDiff,res;
    int sects[SECT_MAX];
    HeadIndex headIndex[INDEX_MAX];
    long nowTime;
    short oSize, hSize, sectNum, memoNum, size,streamNum;
    char terName[20],tempFileName[50],path[50];
    Zone myZone;

    //在打开文件表中查找此文件  
    i=getMemoNum(filename);
    if(i==FAIL) return FAIL;
    
    getMemoZone(&myZone);
    //判断此文件是否读脏
    if (myZone.openFileMemo[i].mod == 1) { //读脏
        time(&nowTime);
        oSize = myZone.openFileMemo[i].size;
        if (isRemote(filename,terName,path)!=SUCCESS)
            strcpy(path,filename);
        loadHeadIndex(headIndex,terName);
        j = getHeadNode(headIndex, path);
        hSize = headIndex[j].size;
        if(oSize < hSize){
            sectDiff=hSize-oSize;
            for (k=0;k<sectDiff;k++){
                sects[k]=headIndex[j].sects[k+oSize];
            }
            res=delSects(sects,sectDiff,terName);
            getMemoZone(&myZone);
            if(res==FAIL) return FAIL;
        }
        else if (oSize > hSize) {
            sectDiff=oSize-hSize;
            res=getVacSects(sects,sectDiff,terName);
            getMemoZone(&myZone);
            if(res==FAIL) return FAIL;
            if(res==NO_HD_ROOM){
                if(strcmp(terName,"\0")){
                    printf("The Content of this file is TOO LONG, please re-edit it, and then try again.\n");
                    return FAIL;
                }
                else{
                    printf("There is NO ROOM in the harddisk, please delete some files, and then try again.\n");
                    return FAIL;
                }
            }
            for (int k=0; k<sectDiff; k++) {
               // res = getVacSects(vNum,terName);                 
                myZone.openFileMemo[i].sectMemo[hSize+k][0] = sects[k];
                headIndex[j].sects[hSize+k] = sects[k];
                headIndex[j].size = headIndex[j].size + 1;
            }
        }
        for(k=0;k<oSize;k++){
                sectNum=myZone.openFileMemo[i].sectMemo[k][0];
                memoNum=myZone.openFileMemo[i].sectMemo[k][1];
                writeBack(myZone.strMemo[memoNum],sectNum,terName);
                unloadMemo(&myZone,memoNum);
        }
        headIndex[j].modTime=nowTime;
        headIndex[j].size=oSize;
        headIndex[j].wrtCnt--;
        unloadHeadIndex(headIndex,terName);

    } else { //未读脏
        size = myZone.openFileMemo[i].size;
        for (j = 0; j < size; j++) {
            memoNum = myZone.openFileMemo[i].sectMemo[j][1];
            unloadMemo(&myZone,memoNum);
        }

        if (isRemote(filename,terName,path)!=SUCCESS){ 
            strcpy(path,filename);
        }
        loadHeadIndex(headIndex,terName);
        j = getHeadNode(headIndex, path);
        if (myZone.openFileMemo[i].loadType <= 2) 
            headIndex[j].wrtCnt--;
        else                    
            headIndex[j].rdCnt--;
        unloadHeadIndex(headIndex,terName);
    }
    myZone.openFileMemo[i].access = FAIL;
    strcpy(myZone.openFileMemo[i].name, "\0");
    myZone.openedSum--;
    putMemoZone(&myZone);
    return SUCCESS;
       

}


///////////////////////////////////////
//
//    			Delete File
//
///////////////////////////////////////

int deleteFile(char *filename) {
    int i, j, n, temp, inode,sects[SECT_MAX];
    short size, vNum,res;
    char tempBuff[50], affirm;
    HeadIndex headIndex[INDEX_MAX];
    Zone myZone;

    int fileOpenNum, dirOpenNum, memoNum;
    char dir[50], file[20], stream[CONTENT_MAX];

    printf("\n**********************************\n");
    printf("    CONFIRM:[Y]Delete [N]Cancel");
    printf("\n**********************************\n");
    while (1) {
        affirm=getche();
        printf("\n");
        if (affirm == 'y' || affirm == 'Y')
            break;
        else if (affirm == 'n' || affirm == 'N')
            return FAIL;
        else
            printf("The value you entered is NOT valid, please input again:");
    }

    //divide dir and file
    n = strlen(filename);
    strcpy(dir, filename);
    for (i = n - 1; i >= 0; i--) {
        if (dir[i] == '/') {
            if (i != 0)
                dir[i] = '\0';
            break;
        }
    }
    j = 0;
    temp = i;
    for (i = i + 1; i < n; i++) {
        file[j] = dir[i];
        j++;
    }
    file[j] = '\0';
    dir[temp + 1] = '\0';


    fileOpenNum = loadFile(filename, RANDW);
    dirOpenNum = loadFile(dir, RANDW);
    if (fileOpenNum == FAIL) {
        if (dirOpenNum != FAIL) unloadFile(dir);
        return FAIL;
    }
    if (dirOpenNum == FAIL) {
        unloadFile(filename);
        return FAIL;
    }
    
    getMemoZone(&myZone);
    if(myZone.openFileMemo[fileOpenNum].type==TYPE_DIR){
        memoNum = myZone.openFileMemo[fileOpenNum].sectMemo[0][1];
        strcpy(stream, myZone.strMemo[memoNum]);
        if (strcmp(stream, "-------") != 0) {
            printf("The directory is NOT empty!\n");
            unloadFile(dir);
            unloadFile(filename);
            return FAIL;
        }
    }

    
    loadHeadIndex(headIndex,"\0");
    inode = getHeadNode(headIndex, filename);
   // if(inode==FAIL)return FAIL;
    size = headIndex[inode].size;
    
     //撤销磁盘空间and memo
    for (j = 0; j < size; j++) 
        sects[j]=headIndex[inode].sects[j];  
    res=delSects(sects,size,"\0");
    while(res==FAIL) {
        printf("Press any key to try again!\n");
        getche();
        printf("\n");
        res=delSects(sects,size,"\0");
    }
    for(j=0;j<size;j++)
        unloadMemo(&myZone,myZone.openFileMemo[fileOpenNum].sectMemo[j][1]);
    
    //改头索引
    strcpy(headIndex[inode].name, "\0");
    headIndex[inode].type = TYPE_NONE;
    unloadHeadIndex(headIndex,"\0");

    //在上一层的目录文件中删除该文件信息
    putMemoZone(&myZone);
    delFileInDir(dirOpenNum, file);
    unloadFile(dir);
    getMemoZone(&myZone);
    myZone.openFileMemo[fileOpenNum].access = FAIL;
    strcpy(myZone.openFileMemo[fileOpenNum].name, "\0");
    myZone.openedSum--;
    putMemoZone(&myZone);
    return SUCCESS;
}


////////////////////////////////////////
//
//               Show File
//
////////////////////////////////////////

int showFile(char *filename) {
    int i, j;
    short size, memoNum;
    char terName[20],path[50];
    Zone myZone;

    //判断是否在/sys及其目录下
    if (isRemote(filename,terName,path)==SUCCESS){
        if(isSys(path)){
            printf("NO PERMISSION to show file %s:/sys or file in %s:/sys\n",terName,terName);
            return FAIL;
        }    
    }else{
        if(isSys(filename)){
            printf("NO PERMISSION to show file /sys or file in /sys\n");
            return FAIL;
        }
    }
        
    i=getMemoNum(filename);
    if(i==FAIL) return FAIL;

    getMemoZone(&myZone);
    if (myZone.openFileMemo[i].loadType == WRITE) {
        printf("The load type does NOT match!\n");
        return FAIL;
    }

    size = myZone.openFileMemo[i].size;
    for (j = 0; j < size; j++) {
        memoNum = myZone.openFileMemo[i].sectMemo[j][1];
        printf("%s",myZone.strMemo[memoNum]);
    }
    printf("\n");
    return SUCCESS;

}


////////////////////////////////////////////
//
//				     Edit File
//
///////////////////////////////////////////

int editFile(char *filename) {
    int i; 
    char ctype;
    short loadType;
    char newStream[CONTENT_MAX * SECT_MAX - SECT_MAX];
    char terName[20],path[50];
    Zone myZone;
    
    //判断是否在/sys及其目录下
    if (isRemote(filename,terName,path)==SUCCESS){
        if(isSys(path)){
            printf("NO PERMISSION to show file /sys or file in /sys\n");
            return FAIL;
        }    
    }else{
        if(isSys(filename)){
            printf("NO PERMISSION to show file /sys or file in /sys\n");
            return FAIL;
        }
    }

     i=getMemoNum(filename);
    if(i==FAIL) return FAIL;
   
     getMemoZone(&myZone);
    if (myZone.openFileMemo[i].type == TYPE_DIR) {
        printf("NO PERMISSION to edit a directory!");
        return FAIL;
    }
     
    printf("Please input the number of type of edit:\n");
    printf("1.Edit freely(type of loading should be READ AND WRITE)\n");
    printf("2.Replace\n");
    printf("3.Append\n");
    printf("Number:");
    while (1) {
        ctype=getche();
        printf("\n");
        if (!(ctype > '0' && ctype < '4'))
            printf("The value you entered is NOT valid, please input again!!\n");
        else
            break;
    }


    //检测打开方式
    loadType = myZone.openFileMemo[i].loadType;
    if (loadType == 3 || ctype-'0' < loadType) {
        printf("The load type does NOT match!\n");
        return FAIL;
    }

    if (ctype == '1') {
        printf("Previous content:\n");
        showFile(filename);
        printf("\n\nPlease input new content:\n");
        gets(newStream);
        replaceContent(newStream, i);
    } else if (ctype == '2') {
        printf("Please input new content(less than %d characters):\n", CONTENT_MAX * SECT_MAX - SECT_MAX);
        gets(newStream);
        replaceContent(newStream, i);
    } else {
        printf("Please input content appending(less than %d characters):\n", CONTENT_MAX * SECT_MAX - SECT_MAX);
        gets(newStream);
        appendContent(newStream, i);
    }
    return SUCCESS;

}



